/* Copyright (c) 2010 Fabian Kulman
* 
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* 
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
* 
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

#include <cmath>
#include <iostream>

#include "space.h"

Space::Space( std::vector<cpFloat>* input ):mousePoint(cpv(0.0f,0.0f)), oldMousePoint(cpv(0.0f,0.0f)){
	cpInitChipmunk();

	ticks = 0; 
	mouseBody = cpBodyNew(INFINITY, INFINITY);
	cpResetShapeIdCounter();

	// Initializing space and hash
	activeSpace = cpSpaceNew();
	activeSpace->iterations = 500;			// Number of iterations to use in the impulse solver to solve contacts
	activeSpace->elasticIterations = 500;	// Number of iterations to use in the impulse solver to solve elastic collisions
	activeSpace->gravity = cpv( 0, 0);		// Default gravity to supply when integrating rigid body motions
	activeSpace->damping = 10.0;			

	cpSpaceResizeStaticHash(activeSpace, 1.2*SCALE, 100);
	cpSpaceResizeActiveHash(activeSpace, 1.2*SCALE, 100);

	// Initializing chain
	chain = Chain::SpaceAddChain( activeSpace, input );
}

Space::~Space(){
	delete chain;
	delete mouseBody;

	destroySpace();
}


void Space::drawSpace(cpSpace *activeSpace, drawSpaceOptions *options){

	chain->drawChain(options->scaleFactor);

	if(options->drawHash)
		drawSpatialHash(activeSpace->activeShapes);

	if(options->drawBBs){
		glLineWidth(1.0f);
		glColor3f(0.3f, 0.5f, 0.3f);
		cpSpaceHashEach(activeSpace->activeShapes, &drawBB, NULL);
		cpSpaceHashEach(activeSpace->staticShapes, &drawBB, NULL);
	}

	glPointSize(7.5f / options->scaleFactor);
	glBegin(GL_POINTS); {
		glColor3f( 1.0f, 1.0f, 0.0f );
		cpArrayEach(activeSpace->arbiters, &drawCollisions, NULL);
	} glEnd();
}


/* Copyright (c) 2007 Scott Lembcke
* 
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* 
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
* 
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

void Space::updateSpace(int ticks){
	int steps = 3; 
	cpFloat dt = 1.0f/60.0f/(cpFloat)steps;

	for(int i=0; i<steps; i++){
		cpSpaceStep(activeSpace, dt);
	}
}


void Space::destroySpace(void){
	cpSpaceFreeChildren(activeSpace);
	cpSpaceFree(activeSpace);
}


inline cpHashValue Space::hash_func(cpHashValue x, cpHashValue y, cpHashValue n){
	return (x*1640531513ul ^ y*2654435789ul) % n;
}


void Space::drawSpatialHash(cpSpaceHash *hash){
	cpBB bb = cpBBNew(-320, -240, 320, 240);

	cpFloat dim = hash->celldim;
	int n = hash->numcells;

	int l = (int)floor(bb.l/dim);
	int r = (int)floor(bb.r/dim);
	int b = (int)floor(bb.b/dim);
	int t = (int)floor(bb.t/dim);

	for(int i=l; i<=r; i++){
		for(int j=b; j<=t; j++){
			int cell_count = 0;

			int index = hash_func(i,j,n);
			for(cpSpaceHashBin *bin = hash->table[index]; bin; bin = bin->next)
				cell_count++;

			GLfloat v = 1.0f - (GLfloat)cell_count/10.0f;
			glColor4f(v,v,v,0.2);
			glRectf(i*dim, j*dim, (i + 1)*dim, (j + 1)*dim);
		}
	}
}


